package com.duoqin.syncassistant.ui;

import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.annotation.Nullable;
import android.support.v4.content.FileProvider;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.widget.ListPopupWindow;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.PopupWindow;
import android.widget.TextView;
import android.widget.Toast;

import com.android.contacts.ContactsQuery;
import com.android.contacts.vcard.ExportProcessor;
import com.android.contacts.vcard.ProcessorBase;
import com.duoqin.account.DuoqinAccount;
import com.duoqin.common.data.DefaultResponse;
import com.duoqin.syncassistant.R;
import com.duoqin.syncassistant.SyncAssistantApplication;
import com.duoqin.syncassistant.Utils;
import com.duoqin.syncassistant.data.BackupFileDownloadResponse;
import com.duoqin.syncassistant.data.BackupFileInfo;
import com.duoqin.syncassistant.viewmodel.BaseViewModel;
import com.duoqin.syncassistant.viewmodel.VCardSyncViewModel;

import java.io.File;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;

public class ContactsSyncActivity extends BaseSyncActivity {

    private VCardSyncViewModel mViewModel;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setupTitle(getString(R.string.contacts_sync));
        mServerRecordsCountView.setText(
                String.valueOf(SyncAssistantApplication.getsInstance().mVCardInfo.getCount()));

        mBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (ExportProcessor.INTENT_ACTION_VCARD.equals(action)) {
                    String vCardPath = intent.getStringExtra(ExportProcessor.INTENT_EXTRA_VCARD_PATH);
                    Log.d(TAG, "vCardPath = " + vCardPath);
                    if (vCardPath != null) {
                        mViewModel.backupVCard(DuoqinAccount.getAccountToken(context),
                                mPhoneRecordsCount, vCardPath);
                    } else {
                        Toast.makeText(getApplicationContext(), R.string.vcard_generic_failure,
                                Toast.LENGTH_SHORT).show();
                        showProgress(false);
                    }
                }
            }
        };

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ExportProcessor.INTENT_ACTION_VCARD);
        LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, intentFilter);
    }

    @Override
    protected void queryLocalRecords() {
        ContentResolver resolver = getContentResolver();
        Cursor contactsCursor = null;
        try {
            contactsCursor = resolver.query(ContactsContract.Contacts.CONTENT_URI,
                    ContactsQuery.PROJECTION, null, null, null);
            if (contactsCursor != null && contactsCursor.moveToFirst()) {
                mRecordIds.clear();
                do {
                    mRecordIds.add(contactsCursor.getString(ContactsQuery.CONTACT_ID));
                } while (contactsCursor.moveToNext());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (contactsCursor != null) {
                contactsCursor.close();
            }
        }
        mPhoneRecordsCount = mRecordIds.size();
        mPhoneRecordsCountView.setText(String.valueOf(mPhoneRecordsCount));
        Log.d(TAG, "Contacts Count = " + mPhoneRecordsCount);
    }

    @Override
    protected void setupModelObserver() {
        mViewModel = ViewModelProviders.of(this).get(VCardSyncViewModel.class);

        final Observer<DefaultResponse> vCardBackupObserver = new Observer<DefaultResponse>() {
            @Override
            public void onChanged(@Nullable DefaultResponse response) {
                Log.i(TAG, "onChanged vCardBackupResponse = " + response);
                if (response != null) {
                    Log.d(TAG, "onChanged code = " + response.getCode()
                            + "; msg = " + response.getMsg());
                    Log.d(TAG, "onChanged data = " + response.getData());
                    if (BaseViewModel.SERVER_RESULT_SUCCESS == response.getCode()) {
                        Toast.makeText(getApplicationContext(), R.string.backup_success,
                                Toast.LENGTH_SHORT).show();
                        setResult(RESULT_OK);
                        finish();
                        return;
                    }
                    Toast.makeText(getApplicationContext(), R.string.backup_fail,
                            Toast.LENGTH_SHORT).show();
                }
                showProgress(false);
            }
        };
        mViewModel.vcardBackupResponse().observe(this, vCardBackupObserver);

        final Observer<BackupFileDownloadResponse> vCardDownloadObserver =
                new Observer<BackupFileDownloadResponse>() {
            @Override
            public void onChanged(@Nullable BackupFileDownloadResponse response) {
                Log.i(TAG, "onChanged BackupFileDownloadResponse = " + response);
                if (response != null) {
                    if (BaseViewModel.SERVER_RESULT_SUCCESS == response.getCode()) {
                        String vCardPath = response.getPath();
                        Log.i(TAG, "onChanged vCardPath = " + vCardPath);
                        Intent importIntent = new Intent(Intent.ACTION_VIEW);
                        importIntent.setPackage("com.android.contacts");
                        final Uri contentUri = FileProvider.getUriForFile(getApplicationContext(),
                                getString(R.string.file_provider_authority),
                                new File(vCardPath));
                        importIntent.setDataAndType(contentUri, "text/x-vcard");
                        importIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
                                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                        importIntent.putExtra("account_name",
                                Utils.LOCAL_CONTACT_ACCOUNT_NAME);
                        importIntent.putExtra("account_type",
                                Utils.LOCAL_CONTACT_ACCOUNT_TYPE);
                        importIntent.addCategory(Intent.CATEGORY_DEFAULT);
                        importIntent.putExtra("should_delete_vcard_file", true);
                        startActivity(importIntent);
                        finish();
                        return;
                    }
                    Toast.makeText(getApplicationContext(), R.string.restore_fail,
                            Toast.LENGTH_SHORT).show();
                }
                showProgress(false);
            }
        };
        mViewModel.downloadVCardResponse().observe(this, vCardDownloadObserver);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
    }

    @Override
    public void onClick(View v) {
        if (R.id.backup_records == v.getId()) {
            attemptBackup();
        } else if (R.id.restore_records == v.getId()) {
            attemptRestore();
        } else {
            super.onClick(v);
        }
    }

    @Override
    protected void attemptRestore() {
        if (SyncAssistantApplication.getsInstance().mAllVCards.size() > 1) {
            LayoutInflater inflater = LayoutInflater.from(getApplicationContext());
            vCardsAdapter vCardsAdapter = new vCardsAdapter(this, inflater);
            if (mListPopupWindow == null) {
                mListPopupWindow = new ListPopupWindow(this);
                mListPopupWindow.setAnchorView(findViewById(R.id.info_panel));
                mListPopupWindow.setAdapter(vCardsAdapter);
                mListPopupWindow.setModal(true);
                mListPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                        position = position - mListPopupWindow.getListView().getHeaderViewsCount();
                        if (position < SyncAssistantApplication.getsInstance().mAllVCards.size()) {
                            BackupFileInfo vCardInfo = SyncAssistantApplication.getsInstance().mAllVCards
                                    .get(position);
                            if (!TextUtils.isEmpty(vCardInfo.getPath())) {
                                showProgress(true);
                                mViewModel.downloadVCard(vCardInfo.getPath(), vCardInfo.getHash());
                            }
                        }
                        mListPopupWindow.dismiss();
                    }
                });
                mListPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
                    @Override
                    public void onDismiss() {
                        mDimBgView.setVisibility(View.GONE);
                    }
                });
                mListPopupWindow.show();
            }
            if (mListPopupWindow.getListView() == null) {
                mListPopupWindow.show();
            }
            if (0 == mListPopupWindow.getListView().getHeaderViewsCount()) {
                View titleView = inflater.inflate(R.layout.list_records_title,
                        mListPopupWindow.getListView(), false);
                mListPopupWindow.getListView().addHeaderView(titleView, null, false);
            }
            if (0 == mListPopupWindow.getListView().getFooterViewsCount()) {
                View footerView = inflater.inflate(R.layout.list_records_footer,
                        mListPopupWindow.getListView(), false);
                mListPopupWindow.getListView().addFooterView(footerView, null, false);
            }
            mListPopupWindow.show();
            mDimBgView.setVisibility(View.VISIBLE);
        } else {
            if (!TextUtils.isEmpty(SyncAssistantApplication.getsInstance().mVCardInfo.getPath())) {
                showProgress(true);
                mViewModel.downloadVCard(SyncAssistantApplication.getsInstance().mVCardInfo.getPath(),
                        SyncAssistantApplication.getsInstance().mVCardInfo.getHash());
            } else {
                Toast.makeText(getApplicationContext(), R.string.restore_vcard_not_found,
                        Toast.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    protected void attemptBackup() {
        showProgress(true);
        if (mPhoneRecordsCount > 0) {
            generateVCard(mRecordIds);
        } else {
            Toast.makeText(getApplicationContext(), R.string.fail_reason_no_exportable_contact,
                    Toast.LENGTH_SHORT).show();
            showProgress(false);
        }
    }

    private synchronized void generateVCard(ArrayList<String> contactIds) {
        if (tryExecute(new ExportProcessor(this, contactIds))) {
            Log.w(TAG, "export success");
        } else {
            Log.w(TAG, "export fail");
        }
    }

    /**
     * Tries to call {@link ExecutorService#execute(Runnable)} toward a given processor.
     * @return true when successful.
     */
    private synchronized boolean tryExecute(ProcessorBase processor) {
        try {
            Log.d(TAG, "Executor service status: shutdown: " + mExecutorService.isShutdown()
                    + ", terminated: " + mExecutorService.isTerminated());
            mExecutorService.execute(processor);
            return true;
        } catch (RejectedExecutionException e) {
            Log.w(TAG, "Failed to excetute a job.", e);
            return false;
        }
    }

    private final static class vCardsAdapter extends BaseAdapter {
        private final Context mContext;
        private final LayoutInflater mInflater;

        public vCardsAdapter(Context context, LayoutInflater inflater) {
            mContext = context;
            mInflater = inflater;
        }

        @Override
        public int getCount() {
            return SyncAssistantApplication.getsInstance().mAllVCards.size();
        }

        @Override
        public Object getItem(int position) {
            return SyncAssistantApplication.getsInstance().mAllVCards.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            final View resultView =
                    (convertView != null) ? convertView
                            : mInflater.inflate(R.layout.list_item_record, parent, false);
            final TextView createdTimeTV = resultView.findViewById(R.id.created_time);
            final TextView countTV = resultView.findViewById(R.id.records_count);

            BackupFileInfo vCardInfo = SyncAssistantApplication.getsInstance().mAllVCards.get(position);
            createdTimeTV.setText(DateUtils.formatDateTime(mContext, vCardInfo.getCreateAt(),
                    DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE
                            | DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_NUMERIC_DATE));
            countTV.setText(mContext.getString(R.string.items_count_of_record,
                    vCardInfo.getCount()));
            return resultView;
        }
    }
}
